/**
 * @author :    hippo
 * @date :      2023-08-02
 * @copyright   Apache 2.0
*/

#ifndef _LOG_H
#define _LOG_H

#include <mutex>
#include <string>
#include <thread>
#include <sys/time.h>
#include <stdarg.h>
#include <assert.h>
#include <sys/stat.h>
#include "log/block_queue.h"
#include "buffer/buffer.h"

class Log {
private:
    static const int LOG_PATH_LEN = 256;
    static const int LOG_NAME_LEN = 256;
    static const int MAX_LINES = 50000;

    const char* path_;
    const char* suffix_;

    int MAX_LINES_;
    
    int line_count_;
    int to_day_;
    
    bool is_open_;

    Buffer buff_;
    int level_;
    bool is_async_;

    FILE* fp_;
    std::unique_ptr<BlockDeque<std::string>> deque_;
    std::unique_ptr<std::thread> write_thread_;
    std::mutex mutex_;

public:
    void init(
        int level,
        const char* path = "./log",
        const char* suffix = ".log",
        int max_queue_capacity = 1024);

    static Log* instance();
    static void flushLogThread();

    void write(int level, const char* format, ...);
    void flush();

    int getLevel();
    void setLevel(int level);
    inline bool isOpen() { return is_open_; }

private:
    Log();
    virtual ~Log();
    void appendLogLevelTitle(int level);
    void asyncWrite();
};

#define LOG_BASE(level, format, ...) \
    do { \
        Log* log = Log::instance(); \
        if(log->isOpen() && log->getLevel() <= level) { \
            log->write(level, format, ##__VA_ARGS__); \
            log->flush(); \
        } \
    } while(0); \

#define LOG_DEBUG(format, ...)  do { LOG_BASE(0, format, ##__VA_ARGS__) } while(0);
#define LOG_INFO(format, ...)   do { LOG_BASE(1, format, ##__VA_ARGS__) } while(0);
#define LOG_WARN(format, ...)   do { LOG_BASE(2, format, ##__VA_ARGS__) } while(0);
#define LOG_ERROR(format, ...)  do { LOG_BASE(3, format, ##__VA_ARGS__) } while(0);

#endif // _LOG_H
